home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / keypad.c < prev    next >
C/C++ Source or Header  |  2001-06-23  |  25KB  |  892 lines

  1. /*
  2.  * Copyright 1993, 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    keypad.c
  12.  *        This module handles the keypad with buttons for each of the
  13.  *        3270 function keys.
  14.  */
  15.  
  16. #include "globals.h"
  17.  
  18. #if defined(X3270_KEYPAD) /*[*/
  19.  
  20. #include <X11/Shell.h>
  21. #include <X11/StringDefs.h>
  22. #include <X11/Xaw/Command.h>
  23. #include "appres.h"
  24. #include "resources.h"
  25.  
  26. #include "actionsc.h"
  27. #include "keypadc.h"
  28. #include "kybdc.h"
  29. #include "menubarc.h"
  30. #include "popupsc.h"
  31. #include "screenc.h"
  32. #include "utilc.h"
  33.  
  34. #include "keypad.bm"
  35.  
  36. enum kp_placement kp_placement;
  37.  
  38. #define NUM_ROWS    4
  39. #define NUM_VROWS    15
  40. #define BORDER        1
  41. #define TOP_MARGIN    6
  42. #define BOTTOM_MARGIN    6
  43.  
  44. #define SPACING        2
  45. #define FAT_SPACING    3
  46. #define VGAP        4
  47. #define HGAP        4
  48. #define SIDE_MARGIN    4
  49.  
  50. #define HORIZ_WIDTH \
  51.     (SIDE_MARGIN + \
  52.      12*(pf_width+2*BORDER) + \
  53.      11*SPACING + \
  54.      HGAP + \
  55.      3*(pa_width+2*BORDER) + \
  56.      2*SPACING + \
  57.      SIDE_MARGIN)
  58.  
  59. #define VERT_WIDTH \
  60.     (SIDE_MARGIN + \
  61.      3*(pa_width+2*BORDER) + \
  62.      2*SPACING + \
  63.      SIDE_MARGIN)
  64.  
  65. /*
  66.  * Table of 3278 key labels and actions
  67.  */
  68. struct button_list {
  69.     const char *label;
  70.     const char *name;
  71.     const char *bits;
  72.     int width;
  73.     int height;
  74.     XtActionProc action;
  75.     const char *parm;
  76. };
  77.  
  78. Boolean keypad_changed = False;
  79.  
  80. static char Lg[] = "large";
  81. static char Bm[] = "bm";
  82. static char Sm[] = "small";
  83.  
  84. static struct button_list pf_list[] = {
  85.     { "PF13",           Lg, CN, 0, 0, PF_action,       "13" },
  86.     { "PF14",           Lg, CN, 0, 0, PF_action,       "14" },
  87.     { "PF15",           Lg, CN, 0, 0, PF_action,       "15" },
  88.     { "PF16",           Lg, CN, 0, 0, PF_action,       "16" },
  89.     { "PF17",           Lg, CN, 0, 0, PF_action,       "17" },
  90.     { "PF18",           Lg, CN, 0, 0, PF_action,       "18" },
  91.     { "PF19",           Lg, CN, 0, 0, PF_action,       "19" },
  92.     { "PF20",           Lg, CN, 0, 0, PF_action,       "20" },
  93.     { "PF21",           Lg, CN, 0, 0, PF_action,       "21" },
  94.     { "PF22",           Lg, CN, 0, 0, PF_action,       "22" },
  95.     { "PF23",           Lg, CN, 0, 0, PF_action,       "23" },
  96.     { "PF24",           Lg, CN, 0, 0, PF_action,       "24" },
  97.     { "PF1",            Lg, CN, 0, 0, PF_action,       "1" },
  98.     { "PF2",            Lg, CN, 0, 0, PF_action,       "2" },
  99.     { "PF3",            Lg, CN, 0, 0, PF_action,       "3" },
  100.     { "PF4",            Lg, CN, 0, 0, PF_action,       "4" },
  101.     { "PF5",            Lg, CN, 0, 0, PF_action,       "5" },
  102.     { "PF6",            Lg, CN, 0, 0, PF_action,       "6" },
  103.     { "PF7",            Lg, CN, 0, 0, PF_action,       "7" },
  104.     { "PF8",            Lg, CN, 0, 0, PF_action,       "8" },
  105.     { "PF9",            Lg, CN, 0, 0, PF_action,       "9" },
  106.     { "PF10",           Lg, CN, 0, 0, PF_action,       "10" },
  107.     { "PF11",           Lg, CN, 0, 0, PF_action,       "11" },
  108.     { "PF12",           Lg, CN, 0, 0, PF_action,       "12" }
  109. };
  110. #define PF_SZ (sizeof(pf_list)/sizeof(pf_list[0]))
  111.  
  112. static struct button_list pad_list[] = {
  113.     { "PA1",            Lg, CN, 0, 0, PA_action,       "1" },
  114.     { "PA2",            Lg, CN, 0, 0, PA_action,       "2" },
  115.     { "PA3",            Lg, CN, 0, 0, PA_action,       "3" },
  116.     { 0, 0, 0, 0 },
  117.     { "Up" ,            Bm, (char *)up_bits, up_width, up_height,
  118.                                       Up_action,       CN },
  119.     { 0, 0, 0, 0 },
  120.     { "Left",           Bm, (char *)left_bits, left_width, left_height,
  121.                                       Left_action,     CN },
  122.     { "Home",           Bm, (char *)home_bits, home_width, home_height,
  123.                                       Home_action,     CN },
  124.     { "Right",          Bm, (char *)right_bits, right_width, right_height,
  125.                                       Right_action,    CN },
  126.     { 0, 0, 0, 0 },
  127.     { "Down",           Bm, (char *)down_bits, down_width, down_height,
  128.                                       Down_action,     CN },
  129.     { 0, 0, 0, 0 },
  130. };
  131. #define PAD_SZ (sizeof(pad_list)/sizeof(pad_list[0]))
  132.  
  133. static struct button_list lower_list[] = {
  134.     { "Clear",          Sm, CN, 0, 0, Clear_action,    CN },
  135.     { "Reset",          Sm, CN, 0, 0, Reset_action,    CN },
  136.     { "Ins",            Bm, (char *)ins_bits, ins_width, ins_height,
  137.                                       Insert_action,   CN },
  138.     { "Del",            Bm, (char *)del_bits, del_width, del_height,
  139.                                       Delete_action,   CN },
  140.     { "Erase\nEOF",     Sm, CN, 0, 0, EraseEOF_action, CN },
  141.     { "Erase\nInput",   Sm, CN, 0, 0, EraseInput_action,CN },
  142.     { "Dup",            Sm, CN, 0, 0, Dup_action,      CN },
  143.     { "Field\nMark",    Sm, CN, 0, 0, FieldMark_action,CN },
  144.     { "Sys\nReq",       Sm, CN, 0, 0, SysReq_action,   CN },
  145.     { "Cursor\nSelect", Sm, CN, 0, 0, CursorSelect_action,CN },
  146.     { "Attn",           Sm, CN, 0, 0, Attn_action,     CN },
  147.     { "Compose",        Sm, CN, 0, 0, Compose_action,  CN },
  148.     { "Btab",           Bm, (char *)btab_bits, btab_width, btab_height,
  149.                                       BackTab_action,  CN },
  150.     { "Tab",            Bm, (char *)tab_bits, tab_width, tab_height,
  151.                                       Tab_action,      CN },
  152.     { "Newline",    Bm, (char *)newline_bits, newline_width, newline_height,
  153.                       Newline_action,  CN },
  154.     { "Enter",          Sm, CN, 0, 0, Enter_action,    CN }
  155. };
  156. #define LOWER_SZ (sizeof(lower_list)/sizeof(lower_list[0]))
  157.  
  158. static struct button_list vpf_list[] = {
  159.     { "PF1",            Lg, CN, 0, 0, PF_action,       "1" },
  160.     { "PF2",            Lg, CN, 0, 0, PF_action,       "2" },
  161.     { "PF3",            Lg, CN, 0, 0, PF_action,       "3" },
  162.     { "PF4",            Lg, CN, 0, 0, PF_action,       "4" },
  163.     { "PF5",            Lg, CN, 0, 0, PF_action,       "5" },
  164.     { "PF6",            Lg, CN, 0, 0, PF_action,       "6" },
  165.     { "PF7",            Lg, CN, 0, 0, PF_action,       "7" },
  166.     { "PF8",            Lg, CN, 0, 0, PF_action,       "8" },
  167.     { "PF9",            Lg, CN, 0, 0, PF_action,       "9" },
  168.     { "PF10",           Lg, CN, 0, 0, PF_action,       "10" },
  169.     { "PF11",           Lg, CN, 0, 0, PF_action,       "11" },
  170.     { "PF12",           Lg, CN, 0, 0, PF_action,       "12" },
  171. };
  172. #define VPF_SZ (sizeof(vpf_list)/sizeof(vpf_list[0]))
  173.  
  174. static struct button_list vspf_list[] = {
  175.     { "PF13",           Lg, CN, 0, 0, PF_action,       "13" },
  176.     { "PF14",           Lg, CN, 0, 0, PF_action,       "14" },
  177.     { "PF15",           Lg, CN, 0, 0, PF_action,       "15" },
  178.     { "PF16",           Lg, CN, 0, 0, PF_action,       "16" },
  179.     { "PF17",           Lg, CN, 0, 0, PF_action,       "17" },
  180.     { "PF18",           Lg, CN, 0, 0, PF_action,       "18" },
  181.     { "PF19",           Lg, CN, 0, 0, PF_action,       "19" },
  182.     { "PF20",           Lg, CN, 0, 0, PF_action,       "20" },
  183.     { "PF21",           Lg, CN, 0, 0, PF_action,       "21" },
  184.     { "PF22",           Lg, CN, 0, 0, PF_action,       "22" },
  185.     { "PF23",           Lg, CN, 0, 0, PF_action,       "23" },
  186.     { "PF24",           Lg, CN, 0, 0, PF_action,       "24" },
  187. };
  188. static Widget vpf_w[2][VPF_SZ];
  189.  
  190. static struct button_list vpad_list[] = {
  191.     { 0, 0, 0 },
  192.     { "Up" ,            Bm, (char *)up_bits, up_width, up_height,
  193.                                       Up_action,       CN },
  194.     { 0, 0, 0 },
  195.     { "Left" ,          Bm, (char *)left_bits, left_width, left_height,
  196.                                       Left_action,     CN },
  197.     { "Home",           Bm, (char *)home_bits, home_width, home_height,
  198.                                       Home_action,     CN },
  199.     { "Right" ,         Bm, (char *)right_bits, right_width, right_height,
  200.                                       Right_action,    CN },
  201.     { "Ins",            Bm, (char *)ins_bits, ins_width, ins_height,
  202.                                       Insert_action,   CN },
  203.     { "Down" ,          Bm, (char *)down_bits, down_width, down_height,
  204.                                       Down_action,     CN },
  205.     { "Del",            Bm, (char *)del_bits, del_width, del_height,
  206.                                       Delete_action,   CN },
  207.     { "PA1",            Lg, CN, 0, 0, PA_action,       "1" },
  208.     { "PA2",            Lg, CN, 0, 0, PA_action,       "2" },
  209.     { "PA3",            Lg, CN, 0, 0, PA_action,       "3" },
  210. };
  211. #define VPAD_SZ (sizeof(vpad_list)/sizeof(vpad_list[0]))
  212.  
  213. static struct button_list vfn_list[] = {
  214.     { "Btab",           Bm, (char *)btab_bits, btab_width, btab_height,
  215.                                       BackTab_action,  CN },
  216.     { "Tab",            Bm, (char *)tab_bits, tab_width, tab_height,       
  217.                                       Tab_action,      CN },
  218.     { "Clear",          Sm, CN, 0, 0, Clear_action,    CN },
  219.     { "Reset",          Sm, CN, 0, 0, Reset_action,    CN },
  220.     { "Erase\nEOF",     Sm, CN, 0, 0, EraseEOF_action, CN },
  221.     { "Erase\nInput",   Sm, CN, 0, 0, EraseInput_action,CN },
  222.     { "Dup",            Sm, CN, 0, 0, Dup_action,      CN },
  223.     { "Field\nMark",    Sm, CN, 0, 0, FieldMark_action,CN },
  224.     { "Sys\nReq",       Sm, CN, 0, 0, SysReq_action,   CN },
  225.     { "Cursor\nSelect", Sm, CN, 0, 0, CursorSelect_action,CN },
  226.     { "Attn",           Sm, CN, 0, 0, Attn_action,     CN },
  227.     { "Compose",        Sm, CN, 0, 0, Compose_action,  CN },
  228.     { "Newline",    Bm, (char *)newline_bits, newline_width, newline_height,
  229.                       Newline_action,  CN },
  230.     { "Enter",          Sm, CN, 0, 0, Enter_action,    CN },
  231. };
  232. #define VFN_SZ (sizeof(vfn_list)/sizeof(vfn_list[0]))
  233.  
  234. static Dimension pf_width;
  235. static Dimension key_height;
  236. static Dimension pa_width;
  237. static Dimension key_width;
  238. static Dimension large_key_width;
  239.  
  240. static Position sm_x, sm_y;
  241. static Dimension sm_w, sm_h;
  242.  
  243. static Widget keypad_container = (Widget) NULL;
  244. static XtTranslations keypad_t00 = (XtTranslations) NULL;
  245. static XtTranslations keypad_t0 = (XtTranslations) NULL;
  246. static XtTranslations saved_xt = (XtTranslations) NULL;
  247.  
  248.  
  249. /* Initialize the keypad placement from the keypad resource. */
  250. void
  251. keypad_placement_init(void)
  252. {
  253.     if (!strcmp(appres.keypad, KpLeft))
  254.         kp_placement = kp_left;
  255.     else if (!strcmp(appres.keypad, KpRight))
  256.         kp_placement = kp_right;
  257.     else if (!strcmp(appres.keypad, KpBottom))
  258.         kp_placement = kp_bottom;
  259.     else if (!strcmp(appres.keypad, KpIntegral))
  260.         kp_placement = kp_integral;
  261.     else
  262.         xs_error("Unknown value for %s", ResKeypad);
  263. }
  264.  
  265. /*
  266.  * Callback for keypad buttons.  Simply calls the function pointed to by the
  267.  * client data.
  268.  */
  269. static void
  270. callfn(Widget w unused, XtPointer client_data, XtPointer call_data unused)
  271. {
  272.     struct button_list *keyd = (struct button_list *) client_data;
  273.  
  274.     action_internal(keyd->action, IA_KEYPAD, keyd->parm, CN);
  275. }
  276.  
  277. /*
  278.  * Create a button.
  279.  */
  280. static Widget
  281. make_a_button(Widget container, Position x, Position y, Dimension w,
  282.     Dimension h, struct button_list *keyd)
  283. {
  284.     Widget command;
  285.     Pixmap pixmap;
  286.  
  287.     if (!keyd->label)
  288.         return (Widget) 0;
  289.  
  290.     command = XtVaCreateManagedWidget(
  291.         keyd->name, commandWidgetClass, container,
  292.         XtNx, x,
  293.         XtNy, y,
  294.         XtNwidth, w,
  295.         XtNheight, h,
  296.         XtNresize, False,
  297.         NULL);
  298.     XtAddCallback(command, XtNcallback, callfn, (XtPointer)keyd);
  299.     if (keyd->bits) {
  300.         pixmap = XCreateBitmapFromData(display, root_window,
  301.             keyd->bits, keyd->width, keyd->height);
  302.         XtVaSetValues(command, XtNbitmap, pixmap, NULL);
  303.     } else
  304.         XtVaSetValues(command, XtNlabel, keyd->label, NULL);
  305.     return command;
  306. }
  307.  
  308. /*
  309.  * Create the keys for a horizontal keypad
  310.  */
  311. static void
  312. keypad_keys_horiz(Widget container)
  313. {
  314.     unsigned i;
  315.     Position row, col;
  316.     Position x0, y0;
  317.  
  318.     /* PF Keys */
  319.     row = col = 0;
  320.     x0 = SIDE_MARGIN;
  321.     y0 = TOP_MARGIN;
  322.     for (i = 0; i < PF_SZ; i++) {
  323.         (void) make_a_button(container,
  324.             (Position)(x0 + (col*(pf_width+2*BORDER+SPACING))),
  325.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  326.             pf_width,
  327.             key_height,
  328.             &pf_list[i]);
  329.         if (++col >= 12) {
  330.             col = 0;
  331.             row++;
  332.         }
  333.     }
  334.  
  335.     /* Keypad */
  336.     row = col = 0;
  337.     x0 = SIDE_MARGIN + 12*(pf_width+2*BORDER+SPACING) + HGAP;
  338.     y0 = TOP_MARGIN;
  339.     for (i = 0; i < PAD_SZ; i++) {
  340.         (void) make_a_button(container,
  341.             (Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
  342.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  343.             pa_width,
  344.             key_height,
  345.             &pad_list[i]);
  346.         if (++col >= 3) {
  347.             col = 0;
  348.             if (++row == 1)
  349.                 y0 += VGAP;
  350.         }
  351.     }
  352.  
  353.     /* Bottom */
  354.     row = col = 0;
  355.     x0 = SIDE_MARGIN;
  356.     y0 = TOP_MARGIN + 2*(key_height+2*BORDER+SPACING) + VGAP;
  357.  
  358.     for (i = 0; i < LOWER_SZ; i++) {
  359.         (void) make_a_button(container,
  360.             (Position)(x0 + (col*(key_width+2*BORDER+FAT_SPACING))),
  361.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  362.             key_width,
  363.             key_height,
  364.             &lower_list[i]);
  365.         if (++row >= 2) {
  366.             ++col;
  367.             row = 0;
  368.         }
  369.     }
  370. }
  371.  
  372. static Boolean vert_keypad = False;
  373. static Widget spf_container;
  374.  
  375. /*
  376.  * Create the keys for a vertical keypad.
  377.  */
  378. static void
  379. keypad_keys_vert(Widget container)
  380. {
  381.     unsigned i;
  382.     Position row, col;
  383.     Position x0, y0;
  384.     Widget c1, c2;
  385.  
  386.     vert_keypad = True;
  387.  
  388.     /* Container for shifted PF keys */
  389.     spf_container = XtVaCreateManagedWidget(
  390.         "shift", compositeWidgetClass, container,
  391.         XtNmappedWhenManaged, False,
  392.         XtNborderWidth, 0,
  393.         XtNwidth, VERT_WIDTH,
  394.         XtNheight, TOP_MARGIN+4*(key_height+2*BORDER)+3*SPACING,
  395.         NULL);
  396.     if (appres.mono)
  397.         XtVaSetValues(spf_container, XtNbackgroundPixmap, gray, NULL);
  398.     else
  399.         XtVaSetValues(spf_container, XtNbackground, keypadbg_pixel,
  400.             NULL);
  401.  
  402.     /* PF keys */
  403.     if (appres.invert_kpshift) {
  404.         c1 = spf_container;
  405.         c2 = container;
  406.     } else {
  407.         c1 = container;
  408.         c2 = spf_container;
  409.     }
  410.     row = col = 0;
  411.     x0 = SIDE_MARGIN;
  412.     y0 = TOP_MARGIN;
  413.     for (i = 0; i < VPF_SZ; i++) {
  414.         vpf_w[0][i] = make_a_button(c1,
  415.             (Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
  416.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  417.             pa_width,
  418.             key_height,
  419.             &vpf_list[i]);
  420.         vpf_w[1][i] = make_a_button(c2,
  421.             (Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
  422.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  423.             pa_width,
  424.             key_height,
  425.             &vspf_list[i]);
  426.         if (++col >= 3) {
  427.             col = 0;
  428.             row++;
  429.         }
  430.     }
  431.  
  432.     /* Cursor and PA keys */
  433.     for (i = 0; i < VPAD_SZ; i++) {
  434.         (void) make_a_button(container,
  435.             (Position)(x0 + (col*(pa_width+2*BORDER+SPACING))),
  436.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  437.             pa_width,
  438.             key_height,
  439.             &vpad_list[i]);
  440.         if (++col >= 3) {
  441.             col = 0;
  442.             row++;
  443.         }
  444.     }
  445.  
  446.     /* Other keys */
  447.     for (i = 0; i < VFN_SZ; i++) {
  448.         (void) make_a_button(container,
  449.             (Position)(x0 + (col*(large_key_width+2*BORDER+SPACING))),
  450.             (Position)(y0 + (row*(key_height+2*BORDER+SPACING))),
  451.             large_key_width,
  452.             key_height,
  453.             &vfn_list[i]);
  454.         if (++col >= 2) {
  455.             col = 0;
  456.             row++;
  457.         }
  458.     }
  459. }
  460.  
  461. static Dimension
  462. get_keypad_dimension(const char *name)
  463. {
  464.     char *rname;
  465.     char *d;
  466.     long v;
  467.  
  468.     rname = xs_buffer("%s.%s", ResKeypad, name);
  469.     if ((d = get_resource(rname)) == CN)
  470.         xs_error("Cannot find %s resource", ResKeypad);
  471.     XtFree(rname);
  472.     if ((v = strtol(d, (char **)0, 0)) <= 0)
  473.         xs_error("Illegal %s resource", ResKeypad);
  474.     return (Dimension)v;
  475. }
  476.  
  477. static void
  478. init_keypad_dimensions(void)
  479. {
  480.     static Boolean done = False;
  481.  
  482.     if (done)
  483.         return;
  484.     key_height = get_keypad_dimension(ResKeyHeight);
  485.     key_width = get_keypad_dimension(ResKeyWidth);
  486.     pf_width = get_keypad_dimension(ResPfWidth);
  487.     pa_width = get_keypad_dimension(ResPaWidth);
  488.     large_key_width = get_keypad_dimension(ResLargeKeyWidth);
  489.     done = True;
  490. }
  491.  
  492. Dimension
  493. min_keypad_width(void)
  494. {
  495.     init_keypad_dimensions();
  496.     return HORIZ_WIDTH;
  497. }
  498.  
  499. Dimension
  500. keypad_qheight(void)
  501. {
  502.     init_keypad_dimensions();
  503.     return TOP_MARGIN +
  504.         (NUM_ROWS*(key_height+2*BORDER)) + (NUM_ROWS-1)*SPACING + VGAP +
  505.         BOTTOM_MARGIN;
  506. }
  507.  
  508. /*
  509.  * Create a keypad.
  510.  */
  511. Widget
  512. keypad_init(Widget container, Dimension voffset, Dimension screen_width, Boolean floating, Boolean vert)
  513. {
  514.     static Widget key_pad;
  515.     Dimension height;
  516.     Dimension width = screen_width;
  517.     Dimension hoffset;
  518.  
  519.     init_keypad_dimensions();
  520.  
  521.     /* Figure out what dimensions to use */
  522.     if (vert)
  523.         width = VERT_WIDTH;
  524.     else
  525.         width = HORIZ_WIDTH;
  526.  
  527.     if (vert)
  528.         height = TOP_MARGIN +
  529.            (NUM_VROWS*(key_height+2*BORDER)) + (NUM_VROWS-1)*SPACING +
  530.            BOTTOM_MARGIN;
  531.     else
  532.         height = keypad_qheight();
  533.  
  534.     /* Create a container */
  535.     if (screen_width > width)
  536.         hoffset = ((screen_width - width) / (unsigned) 2) & ~1;
  537.     else
  538.         hoffset = 0;
  539.     if (voffset & 1)
  540.         voffset++;
  541.     if (key_pad == (Widget)NULL) {
  542.         key_pad = XtVaCreateManagedWidget(
  543.             "keyPad", compositeWidgetClass, container,
  544.             XtNx, hoffset,
  545.             XtNy, voffset,
  546.             XtNborderWidth, (Dimension) (floating ? 1 : 0),
  547.             XtNwidth, width,
  548.             XtNheight, height,
  549.             NULL);
  550.         if (appres.mono)
  551.             XtVaSetValues(key_pad, XtNbackgroundPixmap, gray,
  552.                 NULL);
  553.         else
  554.             XtVaSetValues(key_pad, XtNbackground, keypadbg_pixel,
  555.                 NULL);
  556.  
  557.         /* Create the keys */
  558.         if (vert)
  559.             keypad_keys_vert(key_pad);
  560.         else
  561.             keypad_keys_horiz(key_pad);
  562.     } else {
  563.         XtVaSetValues(key_pad,
  564.             XtNx, hoffset,
  565.             XtNy, voffset,
  566.             NULL);
  567.     }
  568.  
  569.     return key_pad;
  570. }
  571.  
  572. /*
  573.  * Swap PF1-12 and PF13-24 on the vertical popup keypad, by mapping or
  574.  * unmapping the window containing the shifted keys.
  575.  */
  576. void
  577. keypad_shift(void)
  578. {
  579.     if (!vert_keypad || !XtIsRealized(spf_container))
  580.         return;
  581.  
  582.     if (shifted)
  583.         XtMapWidget(spf_container);
  584.     else
  585.         XtUnmapWidget(spf_container);
  586. }
  587.  
  588.  
  589. /*
  590.  * Keypad popup
  591.  */
  592. Widget keypad_shell = NULL;
  593. Boolean keypad_popped = False;
  594. static Boolean up_once = False;
  595. static Position kset_x, kset_y;
  596. static Position kmove_x, kmove_y;
  597. static Dimension decor_width, decor_height;
  598. static enum { WA_UNKNOWN, WA_ALL, WA_PARTIAL, WA_NONE } wa_mode = WA_UNKNOWN;
  599.  
  600. /*
  601.  * Called when the main screen is first exposed, to pop up the keypad the
  602.  * first time
  603.  */
  604. void
  605. keypad_first_up(void)
  606. {
  607.     if (!appres.keypad_on || kp_placement == kp_integral || up_once)
  608.         return;
  609.     keypad_popup_init();
  610.     popup_popup(keypad_shell, XtGrabNone);
  611. }
  612.  
  613. /* Called when the keypad popup pops up or down */
  614. static void
  615. keypad_updown(Widget w unused, XtPointer client_data,
  616.         XtPointer call_data unused)
  617. {
  618.     appres.keypad_on = keypad_popped = *(Boolean *)client_data;
  619.     if (keypad_popped) {
  620.         up_once = True;
  621.         toplevel_geometry(&sm_x, &sm_y, &sm_w, &sm_h);
  622.         XtVaGetValues(keypad_shell, XtNx, &kset_x, XtNy, &kset_y, NULL);
  623.         wa_mode = WA_UNKNOWN;
  624.     }
  625.     menubar_keypad_changed();
  626. }
  627.  
  628. static Boolean TrueD = True;
  629. static Boolean *TrueP = &TrueD;
  630. static Boolean FalseD = False;
  631. static Boolean *FalseP = &FalseD;
  632. static enum placement *pp;
  633.  
  634. /* Create the pop-up keypad */
  635. void
  636. keypad_popup_init(void)
  637. {
  638.     Widget w;
  639.     Dimension height, width, border;
  640.     Boolean vert = False;
  641.  
  642.     if (keypad_shell != NULL)
  643.         return;
  644.  
  645.     switch (kp_placement) {
  646.         case kp_left:
  647.         vert = True;
  648.         pp = LeftP;
  649.         break;
  650.         case kp_right:
  651.         vert = True;
  652.         pp = RightP;
  653.         break;
  654.         case kp_bottom:
  655.         vert = False;
  656.         pp = BottomP;
  657.         break;
  658.         case kp_integral:    /* can't happen */
  659.         return;
  660.     }
  661.  
  662.     /* Create a popup shell */
  663.  
  664.     keypad_shell = XtVaCreatePopupShell(
  665.         "keypadPopup", transientShellWidgetClass, toplevel,
  666.         NULL);
  667.     XtAddCallback(keypad_shell, XtNpopupCallback, place_popup,
  668.         (XtPointer)pp);
  669.     XtAddCallback(keypad_shell, XtNpopupCallback, keypad_updown,
  670.         (XtPointer) TrueP);
  671.     XtAddCallback(keypad_shell, XtNpopdownCallback, keypad_updown,
  672.         (XtPointer) FalseP);
  673.  
  674.     /* Create a keypad in the popup */
  675.  
  676.     keypad_container = XtVaCreateManagedWidget(
  677.         "container", compositeWidgetClass, keypad_shell,
  678.         XtNborderWidth, 0,
  679.         XtNheight, 10,
  680.         XtNwidth, 10,
  681.         NULL);
  682.     w = keypad_init(keypad_container, 0, 0, True, vert);
  683.  
  684.     /* Fix the window size */
  685.  
  686.     XtVaGetValues(w,
  687.         XtNheight, &height,
  688.         XtNwidth, &width,
  689.         XtNborderWidth, &border,
  690.         NULL);
  691.     height += 2*border;
  692.     width += 2*border;
  693.     XtVaSetValues(keypad_container,
  694.         XtNheight, height,
  695.         XtNwidth, width,
  696.         NULL);
  697.     XtVaSetValues(keypad_shell,
  698.         XtNheight, height,
  699.         XtNwidth, width,
  700.         XtNbaseHeight, height,
  701.         XtNbaseWidth, width,
  702.         XtNminHeight, height,
  703.         XtNminWidth, width,
  704.         XtNmaxHeight, height,
  705.         XtNmaxWidth, width,
  706.         NULL);
  707.  
  708.     /* Make keystrokes in the popup apply to the main window */
  709.  
  710.     save_00translations(keypad_container, &keypad_t00);
  711.     set_translations(keypad_container, (XtTranslations *)NULL, &keypad_t0);
  712.     if (saved_xt != (XtTranslations) NULL) {
  713.         XtOverrideTranslations(keypad_container, saved_xt);
  714.         saved_xt = (XtTranslations) NULL;
  715.     }
  716. }
  717.  
  718. /* Set a temporary keymap. */
  719. void
  720. keypad_set_temp_keymap(XtTranslations trans)
  721. {
  722.     if (keypad_container != (Widget) NULL) {
  723.         if (trans == (XtTranslations)NULL) {
  724.             trans = keypad_t0;
  725.             XtUninstallTranslations(keypad_container);
  726.         }
  727.         XtOverrideTranslations(keypad_container, trans);
  728.         saved_xt = (XtTranslations) NULL;
  729.     } else
  730.         saved_xt = trans;
  731. }
  732.  
  733. /* Change the baseleve keymap. */
  734. void
  735. keypad_set_keymap(void)
  736. {
  737.     if (keypad_container == (Widget)NULL)
  738.         return;
  739.     XtUninstallTranslations(keypad_container);
  740.     set_translations(keypad_container, &keypad_t00, &keypad_t0);
  741. }
  742.  
  743. static void
  744. measure_move(XtPointer closure unused, XtIntervalId *id unused)
  745. {
  746.     Position x, y;
  747.  
  748.     XtVaGetValues(keypad_shell, XtNx, &x, XtNy, &y, NULL);
  749.     if (x != kmove_x || y != kmove_y) {
  750.         if (kmove_x - x < 0 && kmove_y - y < 0) {
  751.             /*
  752.              * The window manager shifts by exactly the decoration
  753.              * size (mwm, olwm).
  754.              */
  755.             wa_mode = WA_ALL;
  756.         } else {
  757.             /*
  758.              * The window manager shifts by something less than the
  759.              * decoration size (twm).
  760.              */
  761.             wa_mode = WA_PARTIAL;
  762.             XtVaSetValues(keypad_shell,
  763.                 XtNx,
  764.                 x + decor_width + (decor_width - (kmove_x - x)),
  765.                 XtNy,
  766.                 y + decor_height + (decor_height - (kmove_y - y)),
  767.                 NULL);
  768.         }
  769.     } else {
  770.         /*
  771.          * The window manager leaves the window exactly where we
  772.          * asked (fvwm).
  773.          */
  774.         XtVaSetValues(keypad_shell,
  775.             XtNx, x + decor_width,
  776.             XtNy, y + decor_height,
  777.             NULL);
  778.         wa_mode = WA_NONE;
  779.     }
  780. }
  781.  
  782. /* Move the keypad. */
  783. void
  784. keypad_move(void)
  785. {
  786.     Position x, y;
  787.     Dimension w, h;
  788.     Position x0, y0;
  789.     Dimension w0, h0;
  790.     Dimension kw0;
  791.  
  792.     if (!keypad_popped)
  793.         return;
  794.  
  795.     toplevel_geometry(&x, &y, &w, &h);
  796.     if (x == sm_x && y == sm_y && w == sm_w && h == sm_h)
  797.         return;
  798.  
  799.     XtVaGetValues(toplevel,
  800.         XtNx, &x0,
  801.         XtNy, &y0,
  802.         XtNwidth, &w0,
  803.         XtNheight, &h0,
  804.         NULL);
  805.     switch (kp_placement) {
  806.         case kp_left:
  807.         XtVaGetValues(keypad_shell, XtNwidth, &kw0, NULL);
  808.         switch (wa_mode) {
  809.             case WA_NONE:
  810.             kmove_x = x0 - kw0 - 2 - (w - w0);
  811.             kmove_y = y0;
  812.             break;
  813.             case WA_PARTIAL:
  814.             kmove_x = x - kw0 - 2 - (w - w0) + decor_width;
  815.             kmove_y = y + decor_height;
  816.             break;
  817.             case WA_ALL:
  818.             case WA_UNKNOWN:
  819.             kmove_x = x - kw0 - 2 - (w - w0);
  820.             kmove_y = y;
  821.             break;
  822.         }
  823.         break;
  824.         case kp_right:
  825.         switch (wa_mode) {
  826.             case WA_NONE:
  827.             kmove_x = x0 + w + 2;
  828.             kmove_y = y0;
  829.             break;
  830.             case WA_PARTIAL:
  831.             kmove_x = x + w + 2 + decor_width;
  832.             kmove_y = y + decor_height;
  833.             break;
  834.             case WA_ALL:
  835.             case WA_UNKNOWN:
  836.             kmove_x = x + w + 2;
  837.             kmove_y = y;
  838.             break;
  839.         }
  840.         break;
  841.         case kp_bottom:
  842.         switch (wa_mode) {
  843.             case WA_NONE:
  844.             kmove_x = x0;
  845.             kmove_y = y0 + h + 2;
  846.             break;
  847.             case WA_PARTIAL:
  848.             kmove_x = x + decor_width;
  849.             kmove_y = y + h + 2 + decor_height;
  850.             break;
  851.             case WA_ALL:
  852.             case WA_UNKNOWN:
  853.             kmove_x = x;
  854.             kmove_y = y + h + 2;
  855.             break;
  856.         }
  857.         break;
  858.         case kp_integral:    /* can't happen */
  859.         return;
  860.     }
  861.     XtVaSetValues(keypad_shell,
  862.         XtNx, kmove_x,
  863.         XtNy, kmove_y,
  864.         NULL);
  865.     if (wa_mode == WA_UNKNOWN)
  866.         XtAppAddTimeOut(appcontext, 250, measure_move, 0);
  867. }
  868.  
  869. /*
  870.  * Handler for ReparentNotify events on the keypad.  If the event is a
  871.  * reparent (as opposed to an un-reparent), measures the dimensions of the
  872.  * window manager decorations and stores them in decor_width and decor_height.
  873.  */
  874. void
  875. PA_ReparentNotify_action(Widget w unused, XEvent *event, String *params unused,
  876.     Cardinal *num_params unused)
  877. {
  878.     XReparentEvent *e = (XReparentEvent *)event;
  879.  
  880.     if (e->parent != root_window) {
  881.         Position x, y;
  882.  
  883.         XtVaGetValues(keypad_shell, XtNx, &x, XtNy, &y, NULL);
  884.         if (x > kset_x && y > kset_y) {
  885.             decor_width = x - kset_x;
  886.             decor_height = y - kset_y;
  887.         }
  888.     }
  889. }
  890.  
  891. #endif /*]*/
  892.